// rle_common.c - RLE 公共函数实现
#include "rle_common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// PackBits 风格的 RLE 常量
#define MAX_PACKET_LITERALS 128 // 数据包中文字的最大数量（控制字节 0 到 127 表示 1 到 128 个文字）
#define MAX_PACKET_RUN_LEN  128 // 数据包中行程的最大长度（控制字节 -1 到 -127 表示长度 2 到 128）

// 写入文字数据包的辅助函数
static int write_literal_packet(FILE *out, unsigned char *buffer, int len, long long *written_size) {
    if (len == 0) return 0;
    // 文字的控制字节：(length - 1)。因此，1 个文字为 0，128 个文字为 127。
    if (fputc((unsigned char)(len - 1), out) == EOF) return -1;
    if (fwrite(buffer, 1, len, out) != (size_t)len) return -1;
    *written_size += (1 + len);
    return 0;
}

// 写入行程数据包的辅助函数
static int write_run_packet(FILE *out, unsigned char ch, int len, long long *written_size) {
    // 行程的控制字节：-(length - 1)。因此，长度为 2 的行程为 -1，长度为 128 的行程为 -127。
    if (fputc((unsigned char)(-(len - 1)), out) == EOF) return -1;
    if (fputc(ch, out) == EOF) return -1;
    *written_size += 2;
    return 0;
}

// RLE 压缩函数 (PackBits 风格)
int rle_compress(FILE *input_stream, FILE *output_stream, long long *compressed_size_out) {
    unsigned char literal_buffer[MAX_PACKET_LITERALS];
    int literal_count = 0;
    long long current_compressed_size = 0;
    int c, next_c;
    int run_char_val; // 使用不同的名称以避免与某些上下文中的 run_char 冲突
    int run_len_val;

    if (input_stream == NULL || output_stream == NULL || compressed_size_out == NULL) {
        return -1; // 无效参数
    }
    *compressed_size_out = 0;

    c = fgetc(input_stream);
    while (c != EOF) {
        next_c = fgetc(input_stream);

        if (c == next_c && next_c != EOF) { // 潜在的行程（至少 2 个字符：c 和 next_c）
            // 如果有待处理的文字，首先将其写出
            if (literal_count > 0) {
                if (write_literal_packet(output_stream, literal_buffer, literal_count, &current_compressed_size) != 0) return -1;
                literal_count = 0;
            }

            run_char_val = c;
            run_len_val = 2; // 我们有 c 和 next_c，它们是相同的
            
            // 读取行程的后续字符
            int temp_c;
            for (;;) {
                temp_c = fgetc(input_stream);
                if (temp_c == run_char_val && run_len_val < MAX_PACKET_RUN_LEN) {
                    run_len_val++;
                } else {
                    // 行程在此结束（字符已更改、EOF 或达到最大行程长度）
                    // temp_c 是中断行程的字符或 EOF。它需要在下一步进行处理。
                    c = temp_c; // 这将是下一个主循环迭代的 'c'
                    break;
                }
            }
            if (write_run_packet(output_stream, (unsigned char)run_char_val, run_len_val, &current_compressed_size) != 0) return -1;
            // 'c' 已由内部循环中的 temp_c 为下一次迭代设置。
            // 主循环 `while(c != EOF)` 将处理它。

        } else { // 不是行程 (c != next_c)，或者 next_c 是 EOF (因此 c 是此上下文中唯一/最后一个字符)
            literal_buffer[literal_count++] = (unsigned char)c;
            if (literal_count == MAX_PACKET_LITERALS) {
                // 文字缓冲区已满，将其写出
                if (write_literal_packet(output_stream, literal_buffer, literal_count, &current_compressed_size) != 0) return -1;
                literal_count = 0;
            }
            c = next_c; // 移动到下一个字符进行处理 (next_c 可能为 EOF，从而终止循环)
        }
    }

    // 循环结束后，如果还有剩余的文字，则将其写出
    if (literal_count > 0) {
        if (write_literal_packet(output_stream, literal_buffer, literal_count, &current_compressed_size) != 0) return -1;
    }

    *compressed_size_out = current_compressed_size;
    return 0;
}

// RLE 解压缩函数 (PackBits 风格)
int rle_decompress(FILE *input_stream, FILE *output_stream, long long compressed_size, long long original_size) {
    long long bytes_read_from_input = 0;
    int control_byte_val; // 已重命名以避免冲突
    int len_val;          // 已重命名以避免冲突
    unsigned char char_val; // 已重命名以避免冲突

    if (input_stream == NULL || output_stream == NULL) return -1;
    // 如果 compressed_size 准确，则 PackBits 解压缩不严格需要 original_size。

    while (bytes_read_from_input < compressed_size) {
        control_byte_val = fgetc(input_stream);
        if (control_byte_val == EOF) {
            // 如果 bytes_read < compressed_size，则为过早的 EOF，除非 compressed_size 为 0 (空文件)
            return (bytes_read_from_input == compressed_size && compressed_size == 0) ? 0 : -1;
        }
        bytes_read_from_input++;

        if ((signed char)control_byte_val >= 0) { // 文字数据包：0 到 127
            len_val = (signed char)control_byte_val + 1; // 实际长度：1 到 128
            for (int i = 0; i < len_val; ++i) {
                if (bytes_read_from_input >= compressed_size) return -1; // 错误：尝试读取超出压缩数据末尾的内容
                int data_byte = fgetc(input_stream);
                if (data_byte == EOF) return -1; // 文字数据内过早的 EOF
                bytes_read_from_input++;
                if (fputc((unsigned char)data_byte, output_stream) == EOF) return -1;
            }
        } else { // 行程数据包：-1 到 -127 (或 -128，即 NOP)
            if ((signed char)control_byte_val == -128) { // PackBits 中的 NOP 字节，跳过它
                // 根据 Adobe PackBits 规范，-128 是一个 NOP。继续处理。
                continue; 
            }
            len_val = -((signed char)control_byte_val) + 1; // 实际长度：2 到 128
            
            if (bytes_read_from_input >= compressed_size) return -1; // 错误：尝试读取超出行程末尾的字符
            int data_byte_for_run = fgetc(input_stream);
            if (data_byte_for_run == EOF) return -1; // 过早的 EOF，应为行程的字符
            bytes_read_from_input++;
            char_val = (unsigned char)data_byte_for_run;

            for (int i = 0; i < len_val; ++i) {
                if (fputc(char_val, output_stream) == EOF) return -1;
            }
        }
    }
    
    // 最终检查：确保所有压缩数据都已使用
    if (bytes_read_from_input != compressed_size) {
        return -1; // 应准确读取 compressed_size 字节
    }

    return 0;
}

// 将条目头写入存档的辅助函数
void write_entry_header(FILE* archive_file, const RzpEntryHeader* header) {
    if (archive_file == NULL || header == NULL) return;
    fwrite(header, sizeof(RzpEntryHeader), 1, archive_file);
}

// 从存档读取条目头的辅助函数
// 如果成功读取头，则返回 1，如果 EOF 或错误，则返回 0
int read_entry_header(FILE* archive_file, RzpEntryHeader* header) {
    if (archive_file == NULL || header == NULL) return 0;
    size_t items_read = fread(header, sizeof(RzpEntryHeader), 1, archive_file);
    if (items_read == 1) {
        return 1;
    }
    if (feof(archive_file)) {
        return 0; // 文件结束
    }
    return -1; // 读取错误
}